/*
@hehung
email: 1398660197@qq.com
wechat: hehung95
reproduced and please indicate the source @hehung
*/

/* P602 - TX
   P601 - RX
*/

#include "app_common.h"


#define ESP8266_DEBUG 
#undef  ESP8266_DEBUG

#ifdef ESP8266_DEBUG
#define LOG(fmt, ... )        printf( fmt, ##__VA_ARGS__ )
#else
#define LOG(fmt, ... )
#endif


#define HOTSPOT_ID             "\"hehungHome\""           // Wifi hotspot name
#define HOTSPOT_PASSWORD       "\"1234543210\""           // Wifi hostpot password
#define HOTSPOT_STRING         HOTSPOT_ID "," HOTSPOT_PASSWORD "\r\n"       

#define SERVER_IP              "\"192.168.6.100\""        // Server IP
#define SERVER_PORT            "8090"                 // Server Port
#define SERVER_STRING          SERVER_IP "," SERVER_PORT "\r\n"


// Aliyun
#define MQTT_SERVICE_ID       "\"a1rgyN0AeMY.test0|securemode=2\\,signmethod=hmacsha256\\,timestamp=1690097540476|\""
#define MQTT_USER_NAME        "\"test0&a1rgyN0AeMY\""
#define MQTT_PASSWORD         "\"d21ed60b5f773333180726dc5f74c4153b066b32fb46a35eb8e5732b37929cb3\""   

#define MQTT_URL              "\"a1rgyN0AeMY.iot-as-mqtt.cn-shanghai.aliyuncs.com\""
#define MQTT_PORT             "1883"

#define MQTT_POST             "\"/sys/a1rgyN0AeMY/test0/thing/event/property/post\""


#define Esp8266_ModuleEnable()     \
            R_IOPORT_PinWrite(&g_ioport_ctrl, BSP_IO_PORT_01_PIN_15, BSP_IO_LEVEL_HIGH)  // Enable ESP8266
#define Esp8266_ModuleDisable()    \
            R_IOPORT_PinWrite(&g_ioport_ctrl, BSP_IO_PORT_01_PIN_15, BSP_IO_LEVEL_LOW)   // Disable ESP8266


/* Clear Uart9 buffer */
#define Esp8266_ClearBuff()       memset(g_at_buf.at_buf ,0 ,sizeof(g_at_buf.at_buf)); \
                                  g_at_buf.at_len = 0;
								  
#define Esp8266_ClearRespBuff()   memset(g_recv_buf.at_buf ,0 ,sizeof(g_recv_buf.at_buf)); \
                                  g_recv_buf.at_len = 0; 


static _Bool uart9_receive_flag = false; 
//static _Bool uart9_show_flag = false;    //控制UART9收发数据显示标志

static uint32_t g_wifi_receive_time_count = 0;

static esp8266_at_rx_t g_at_buf;
static esp8266_at_rx_t g_recv_buf;

/* AT Command sets */
esp8266_at_cmd_set_t esp8266_cmd_set[] =
{
    /* Intial AT command */
    [ESP8266_ATCMD_IDX_STAMODE] =
    {
        .p_cmd = "AT+CWMODE=1\r\n",
        .p_success_resp = (uint8_t *)"OK",
        .max_resp_length = 128,
        .retry = 5,
        .retry_delay = 500,
        .wait_timeout = 2000
    },
	[ESP8266_ATCMD_IDX_ATE0] =
    {
        .p_cmd = "ATE0\r\n",
        .p_success_resp = (uint8_t *)"OK",
        .max_resp_length = 128,
        .retry = 5,
        .retry_delay = 500,
        .wait_timeout = 1000
    },
    [ESP8266_ATCMD_IDX_RESET] =
    {
        .p_cmd = "AT+RST\r\n",
        .p_success_resp = (uint8_t *)"OK",
        .max_resp_length = 128,
        .retry = 5,
        .retry_delay = 500,
        .wait_timeout = 1000
    },
    [ESP8266_ATCMD_IDX_APMODE] =
    {
        .p_cmd = "AT+CWMODE=2\r\n",
        .p_success_resp = (uint8_t *)"OK",
        .max_resp_length = 128,
        .retry = 5,
        .retry_delay = 500,
        .wait_timeout = 1000
    },
    [ESP8266_ATCMD_IDX_APSTAMODE] =
    {
        .p_cmd = "AT+CWMODE=3\r\n",
        .p_success_resp = (uint8_t *)"OK",
        .max_resp_length = 128,
        .retry = 5,
        .retry_delay = 500,
        .wait_timeout = 1000
    },
    [ESP8266_ATCMD_IDX_HOTSPOT_FD] =
    {
        .p_cmd = "AT+CWJAP?",
        .p_success_resp = (uint8_t *)"+CWJAP",
        .max_resp_length = 256,
        .retry = 5,
        .retry_delay = 0,
        .wait_timeout = 0
    },
    [ESP8266_ATCMD_IDX_HOTSPOT] =
    {
        .p_cmd = "AT+CWJAP=" HOTSPOT_STRING,
        .p_success_resp = (uint8_t *)"OK",
        .max_resp_length = 256,
        .retry = 5,
        .retry_delay = 500,
        .wait_timeout = 10000
    },
    [ESP8266_ATCMD_IDX_SINGLELINKMODE] =
    {
        .p_cmd = "AT+CIPMUX=0\r\n",
        .p_success_resp = (uint8_t *)"OK",
        .max_resp_length = 128,
        .retry = 5,
        .retry_delay = 500,
        .wait_timeout = 1000
    },
    [ESP8266_ATCMD_IDX_MULTILINKMODE] =
    {
        .p_cmd = "AT+CIPMUX=1\r\n",
        .p_success_resp = (uint8_t *)"OK",
        .max_resp_length = 128,
        .retry = 5,
        .retry_delay = 500,
        .wait_timeout = 1000
    },
    [ESP8266_ATCMD_IDX_SERVER_CONN] =
    {
        .p_cmd = "AT+CIPSTART=\"TCP\"" "," SERVER_STRING,
        .p_success_resp = (uint8_t *)"OK",
        .max_resp_length = 256,
        .retry = 5,
        .retry_delay = 500,
        .wait_timeout = 10000
    },
    [ESP8266_ATCMD_IDX_TRANSMODE] =
    {
        .p_cmd = "AT+CIPMODE=1\r\n",
        .p_success_resp = (uint8_t *)"OK",
        .max_resp_length = 60,
        .retry = 5,
        .retry_delay = 500,
        .wait_timeout = 1000
    },
    [ESP8266_ATCMD_IDX_SENDDATA] =
    {
        .p_cmd = "AT+CIPSEND\r\n",
        .p_success_resp = (uint8_t *)"OK",
        .max_resp_length = 60,
        .retry = 5,
        .retry_delay = 500,
        .wait_timeout = 1000
    },
    [ESP8266_ATCMD_IDX_SNTPCFG] =
    {
        .p_cmd = "AT+CIPSNTPCFG=1,8\r\n",
        .p_success_resp = (uint8_t *)"OK",
        .max_resp_length = 128,
        .retry = 5,
        .retry_delay = 500,
        .wait_timeout = 1000
    },
    [ESP8266_ATCMD_IDX_GETSNTPTIME] =
    {
        .p_cmd = "AT+CIPSNTPTIME?\r\n",
        .p_success_resp = (uint8_t *)"OK",
        .max_resp_length = 128,
        .retry = 5,
        .retry_delay = 500,
        .wait_timeout = 1000
    },
    [ESP8266_ATCMD_IDX_MQTTUSERCFG] =
    {
        .p_cmd = "AT+MQTTUSERCFG=0,1," MQTT_SERVICE_ID "," MQTT_USER_NAME "," MQTT_PASSWORD ",0,0,\"\"\r\n",
        .p_success_resp = (uint8_t *)"OK",
        .max_resp_length = 512,
        .retry = 5,
        .retry_delay = 500,
        .wait_timeout = 1000
    },
    [ESP8266_ATCMD_IDX_MQTTCONN] =
    {
        .p_cmd = "AT+MQTTCONN=0," MQTT_URL "," MQTT_PORT ",1\r\n",
        .p_success_resp = (uint8_t *)"OK",
        .max_resp_length = 512,
        .retry = 5,
        .retry_delay = 500,
        .wait_timeout = 10000
    },
    [ESP8266_ATCMD_IDX_MQTTPUB] =
    {
        .p_cmd = "AT+MQTTPUB=",
        .p_success_resp = (uint8_t *)"OK",
        .max_resp_length = 512,
        .retry = 5,
        .retry_delay = 500,
        .wait_timeout = 5000
    },
    [ESP8266_ATCMD_IDX_MQTTSUB] =
    {
        .p_cmd = "AT+MQTTSUB=",
        .p_success_resp = (uint8_t *)"OK",
        .max_resp_length = 512,
        .retry = 5,
        .retry_delay = 500,
        .wait_timeout = 5000
    }
};

static void Esp8266_AT_Send(char *cmd, uint16_t len) ;
static fsp_err_t wifi_serial_read(uint8_t * p_dest, 
								   const uint16_t * p_bytes, 
								   const char * p_resp_ptr, 
								   uint32_t timeout_ms);
								   
								   
/* Send AT command to WIFI Module */
static void Esp8266_AT_Send(char *cmd, uint16_t len)  
{
    R_SCI_UART_Write(&g_uart9_ctrl, (uint8_t *)cmd, (uint32_t)len); 
    
    /* Clear received flag after send finished */
    uart9_receive_flag = false;
}

// Esp8266 wifi module AT command
fsp_err_t Esp8266_ATCommandExe(esp8266_at_cmd_index_t at_cmd, 
                                uint8_t *resp_buff)
{
    uint16_t bytes_read = 0U;
    uint16_t bytes_write;
    fsp_err_t result = FSP_ERR_ASSERTION;
    uint8_t retry_count = 0U;
    esp8266_at_cmd_set_t  *p_cmd_set = esp8266_cmd_set;

    // setting mutex for lock wifi uart
    if (pdTRUE == xSemaphoreTake(wifi_mutex, portMAX_DELAY))
    {
        do
        {
			Esp8266_ClearBuff();
            /* Command length */
            bytes_write = (uint16_t) strlen((char *) p_cmd_set[at_cmd].p_cmd);
//			printf ("\r\nSend data is %s, length is %d\r\n", p_cmd_set[at_cmd].p_cmd, bytes_write);
            // wifi_serial_write((uint8_t*)p_cmd_set[at_cmd].p_cmd, bytes_write);
            Esp8266_AT_Send((char *)p_cmd_set[at_cmd].p_cmd, bytes_write);

            bytes_read = p_cmd_set[at_cmd].max_resp_length;

			/** Clear respond memory **/
            memset (resp_buff, '\0', bytes_read);
            result = wifi_serial_read(resp_buff, 
                                      &bytes_read, 
                                      (const char*)p_cmd_set[at_cmd].p_success_resp, 
                                      p_cmd_set[at_cmd].wait_timeout);
//			printf ("Received successfully\r\n");
									  
            if (FSP_SUCCESS == result)
            {
                break;
            }
        
            DELAY_MS(p_cmd_set[at_cmd].retry_delay);

            ++retry_count;
        }
        while(retry_count < p_cmd_set[at_cmd].retry);

        // release the mutex, unlock
        (void)xSemaphoreGive(wifi_mutex);
    }

    return result;
}

/* Compare string */
uint8_t is_str_present(const char * p_resp_str, const char * p_search_str)
{
    if (strstr (p_resp_str, p_search_str))
    {
        return SF_WIFI_TRUE;
    }

    return SF_WIFI_FALSE;
}

/* Read responsed data */
static fsp_err_t wifi_serial_read(uint8_t * p_dest, 
								   const uint16_t * p_bytes, 
								   const char * p_resp_ptr, 
								   uint32_t timeout_ms)
{
    fsp_err_t status = FSP_SUCCESS;
    uint16_t bytes = *p_bytes;
    uint16_t i;
    uint8_t expected_resp_present;
	uint16_t succ_len = (uint16_t)strlen(p_resp_ptr);

    g_wifi_receive_time_count = 0U;

    do
    {
        // some data received from DA16200
        if (g_at_buf.at_len >= succ_len)
        {
            if (g_at_buf.at_len >= bytes)
            {
                /* Overflow */
                status = FSP_ERR_RXBUF_OVERFLOW;
				LOG ("==>esp8266 recv:Overflow\r\n");
                break;
            } 

            // compare the response data
            expected_resp_present = is_str_present(g_at_buf.at_buf, p_resp_ptr);
            if(SF_WIFI_TRUE == expected_resp_present)
            {
                LOG ("==>esp8266 recv:%s\r\n", g_at_buf.at_buf);
                status = FSP_SUCCESS;
                break;
            }
            // memset(g_at_buf.at_buf, '\0', sizeof(g_at_buf.at_buf));
        }

        expected_resp_present = is_str_present(g_at_buf.at_buf, "ERROR");
        if(SF_WIFI_TRUE == expected_resp_present)
        {
            // error
            LOG ("==>esp8266 error:%s\r\n", g_at_buf.at_buf);
            status = FSP_ERR_ASSERTION;
            break;
        }

        // timeout
        if(g_wifi_receive_time_count >= timeout_ms)
        {
			LOG ("===========================\r\n");
			LOG ("%s, %d\r\n", g_at_buf.at_buf, g_at_buf.at_len);
			LOG ("===========================\r\n");
            if (g_at_buf.at_len >= 0)
            {
                Esp8266_ClearBuff();
            }
                
            g_wifi_receive_time_count = 0U;
            status = FSP_ERR_TIMEOUT;
            break;
        }

        /* Added delay for freeRTOS and used for solved thread dead */
        DELAY_MS(1);
    } while(1);

    // load the data to dest buffer
    if (FSP_SUCCESS == status)
    {
        for (i = 0; i < g_at_buf.at_len; i++)
        {
            *p_dest = g_at_buf.at_buf[i];
            p_dest ++;
        }
    }
    
    return status;
}


/* MQTT publisher */
fsp_err_t Esp8266_MqttPost(s_postParamType *post_param)
{
	fsp_err_t err = FSP_SUCCESS;
	char post_data[512];
	
	sprintf(post_data, 
	"AT+MQTTPUB=0,\"/sys/a1rgyN0AeMY/test0/thing/event/property/post\",\"{params:{\\\"temperature\\\":%.2f\\,\\\"humidity\\\":%.2f\\,\\\"MQ5\\\":%d\\,\\\"heartbeat\\\":%d\\,\\\"SpO2\\\":%0.1f\\,\\\"LEDSwitch\\\":%d\\,\\\"Mq5WarnThd\\\":%d\\,\\\"Mq5WarnEn\\\":%d}}\",0,0\r\n",
	        post_param->temp, post_param->humi,
	        post_param->mq5, post_param->heart_beat, 
	        post_param->spo2, post_param->led,
	        post_param->mq5_thd, post_param->warning_switch);
	
	esp8266_cmd_set[ESP8266_ATCMD_IDX_MQTTPUB].p_cmd = &post_data[0];
	
	LOG("==>Send:%s\r\n", post_data);
	
	
	return err;
}

/* MQTT post */
fsp_err_t Esp8266_MqttSubscriber(void)
{
	fsp_err_t err = FSP_SUCCESS;
	char post_data[512];
	
	sprintf(post_data, 
	"AT+MQTTSUB=0,\"/sys/a1rgyN0AeMY/test0/thing/service/property/set\",1\r\n");
	
	esp8266_cmd_set[ESP8266_ATCMD_IDX_MQTTSUB].p_cmd = &post_data[0];
	
	LOG("==>Send:%s\r\n", post_data);
	
	
	return err;
}

void Esp8266_Feedback(void)
{
#define TEMP_STR_LEN              (30U)
	char *find_p;
	char temp_str[TEMP_STR_LEN];
	uint8_t i;
	uint32_t temp_data;
	
	if (g_recv_buf.at_buf[g_recv_buf.at_len-1] == '\n')
	{
		if (g_recv_buf.at_len > 64U)
		{
			if (SF_WIFI_TRUE == is_str_present(g_recv_buf.at_buf, "+MQTTSUBRECV:"))
			{
				// Parse the MQTT command
				find_p = strstr(g_recv_buf.at_buf, "\"LEDSwitch\":");
				if (find_p != NULL)
				{
					memset(temp_str, 0 , TEMP_STR_LEN);
					for (i = 0; i < TEMP_STR_LEN; i++)
					{
						if ((find_p[i] != ',') && (find_p[i] != '}'))
						{
							temp_str[i] = find_p[i];
						}
						else
						{
							break;
						}
					}

					sscanf(temp_str, "\"LEDSwitch\":%d", &temp_data);
					Led_DutyCycleCtrl_Led1((uint8_t)temp_data);
				}
				
				find_p = strstr(g_recv_buf.at_buf, "\"Mq5WarnThd\":");
				if (find_p != NULL)
				{
					memset(temp_str, 0 , TEMP_STR_LEN);
					for (i = 0; i < TEMP_STR_LEN; i++)
					{
						if ((find_p[i] != ',') && (find_p[i] != '}'))
						{
							temp_str[i] = find_p[i];
						}
						else
						{
							break;
						}
					}
					sscanf(temp_str, "\"Mq5WarnThd\":%d", &temp_data);	
					Warning_SetMq5Threshold(temp_data);
				}
				
				find_p = strstr(g_recv_buf.at_buf, "\"Mq5WarnEn\":");
				if (find_p != NULL)
				{
					memset(temp_str, 0 , TEMP_STR_LEN);
					for (i = 0; i < TEMP_STR_LEN; i++)
					{
						if ((find_p[i] != ',') && (find_p[i] != '}'))
						{
							temp_str[i] = find_p[i];
						}
						else
						{
							break;
						}
					}
					sscanf(temp_str, "\"Mq5WarnEn\":%d", &temp_data);
					Warning_SetMq5WarningSwitch((uint8_t)temp_data);
				}
			}		
		}
		
		Esp8266_ClearRespBuff();
	}
}


/*ESP8266 (SPI9 UART) 初始化函数*/
void Esp8266_Init(void)
{
    fsp_err_t err = FSP_SUCCESS;
	
	/* Reset ESP8266 */
	Esp8266_ModuleDisable();
	DELAY_MS(10);
	Esp8266_ModuleEnable();
    
    err = R_SCI_UART_Open(&g_uart9_ctrl, &g_uart9_cfg);
    assert(FSP_SUCCESS == err);
}


/* Wifi uart callback function */
void uart9_notification(uart_callback_args_t * p_args)
{
	switch(p_args->event)
	{
        case UART_EVENT_RX_CHAR:  
        {
            // Put the received data into buffer
			// This buffer is used for AT feedback command
			g_at_buf.at_buf[g_at_buf.at_len++] = (uint8_t ) p_args->data;  
			g_at_buf.at_len = (g_at_buf.at_len > BUFFER_SIZE) ? (0) : (g_at_buf.at_len);
			// This buffer is used for received MQTT Subscribe information
		    g_recv_buf.at_buf[g_recv_buf.at_len++] = (uint8_t ) p_args->data;
			g_recv_buf.at_len = (g_at_buf.at_len > BUFFER_SIZE) ? (0) : (g_recv_buf.at_len);
		   
			Esp8266_Feedback();
		   
			break;	   
	   }	   
	   case UART_EVENT_TX_COMPLETE:
	   {
			uart9_receive_flag = true;      //ESP8266回应完成标志
		   
			break;
	   }
	   default: break;
	}
}

void timer0_1ms_callback(timer_callback_args_t *p_args)
{
    FSP_PARAMETER_NOT_USED(p_args);

    g_wifi_receive_time_count++;
}
